import { Directive, DoCheck, Input, ElementRef, forwardRef, HostListener, OnInit, KeyValueDiffer, KeyValueDiffers } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, NgModel } from '@angular/forms';
import { CurrencyPipe, DecimalPipe } from '@angular/common';
import { InputHandler } from './currency.handler';

export const CURRENCYMASKDIRECTIVE_VALUE_ACCESSOR: any = {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => MyDirective),
  multi: true,
};

@Directive({
  selector: '[appCurrencyInputDit]',
  providers: [CURRENCYMASKDIRECTIVE_VALUE_ACCESSOR, CurrencyPipe],
})
export class MyDirective implements ControlValueAccessor, OnInit, DoCheck {
  @Input() options: any = {};
  optionsTemplate = {
    decimal: '.', // Separator of decimals (default: '.')
    precision: 2, //  Number of decimal places (default: 2)
    currencyCode: 'EUR',
    prefix: '€',
    thousands: ',', // Separator of thousands (default: ',')
  };
  //
  inputHandler: InputHandler;
  keyValueDiffer: KeyValueDiffer<any, any>;
  //
  constructor(private elementRef: ElementRef, private currencyPipe: CurrencyPipe, private keyValueDiffers: KeyValueDiffers) {
    this.keyValueDiffer = keyValueDiffers.find({}).create();
  }
  //
  ngOnInit() {
    this.inputHandler = new InputHandler(
      this.currencyPipe,
      this.elementRef.nativeElement,
      (<any>Object).assign({}, this.optionsTemplate, this.options)
    );
  }

  ngDoCheck() {
    if (this.keyValueDiffer.diff(this.options)) {
      this.inputHandler.updateOptions((<any>Object).assign({}, this.optionsTemplate, this.options));
    }
  }

  // Chinese input is prohibited
  @HostListener('compositionend', ['$event'])
  onCompositionEnd(e: any) {
    this.inputHandler.handleCompositionEnd(e);
  }
  // It is forbidden to input other characters except numbers, decimal point, back key.
  @HostListener('keypress', ['$event'])
  handleKeypress(e: any) {
    this.inputHandler.handleKeypress(e);
  }
  // When the focus is acquired, it is converted to a number.
  @HostListener('focus', ['$event'])
  handleFocus(e: any) {
    this.inputHandler.handleFocus(e);
  }
  // When losing focus, convert to currency format.
  @HostListener('blur', ['$event'])
  onInputChange(e: any) {
    this.inputHandler.handleCompositionBlur(e);
  }

  // ===
  registerOnChange(callbackFunction: Function): void {
    this.inputHandler.setOnModelChange(callbackFunction);
  }

  registerOnTouched(callbackFunction: Function): void {
    this.inputHandler.setOnModelTouched(callbackFunction);
  }

  writeValue(value: any): void {
    this.inputHandler.setValue(value);
  }
}
